package com.engine.modules.ytht.util;

import java.nio.charset.StandardCharsets;
import java.util.Map;
import java.util.Map.Entry;
import java.util.TreeMap;
import java.util.UUID;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.DatatypeConverter;

import com.alibaba.fastjson.JSONObject;

import com.engine.common.util.RestTemplateUtil;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

/**
 * v2版本签名
 *
 */
public class OpenV2SignDemo {

	private static String HMAC_SHA256 = "HmacSHA256";

	public static void main(String[] args) throws Exception {
		String appkey = "TWkiRyQCNqpGTFkS3JISgnOCwezYHgHT"; //
		String appsecret = "o63lO3tUfUniy0eo1Cc3wcZcETrelsOC"; //

		OkHttpClient httpClient = new OkHttpClient().newBuilder().build();

		//用全局标量中的账号信息，申请token，并保存
		RestTemplate restTemplate = new RestTemplate(RestTemplateUtil.GetHttpFactory());
		String url2 = "https://yzstest.ynhtbank.com/dev/gateway/oauth/token/?appkey=" + appkey + "&appsecret=" + appsecret;
		HttpHeaders headers = new HttpHeaders();
		headers.setContentType(org.springframework.http.MediaType.APPLICATION_FORM_URLENCODED);
		MultiValueMap<String, Object> map = new LinkedMultiValueMap<String, Object>();
		HttpEntity<MultiValueMap<String, Object>> httpEntity = new HttpEntity<MultiValueMap<String, Object>>(map, headers);
		String body = restTemplate.getForObject(url2, String.class);
		String accessToken = JSONObject.parseObject(body).getJSONObject("data")
				.getString("accessToken");


		// 排序参数
		Map<String, String> signParams = new TreeMap<>();

		// 业务唯一请求
		String nonce = UUID.randomUUID().toString();// 业务请求唯一性
		String timestamp = String.valueOf(System.currentTimeMillis());
		signParams.put("nonce", nonce);
		signParams.put("timestamp", timestamp);// 5分钟内有效
		signParams.put("appkey", appkey);
		signParams.put("token", accessToken);
		signParams.put("secret", sign(accessToken + appsecret + nonce + timestamp, appsecret, HMAC_SHA256));

//		signParams.put("url参数", "url参数值");
		//以下是 get 请求才需要包含。下面只是例子 signParams.put("code", "烟农业务码")
		signParams.put("code", "5484d3ddd671154439411b8a729cb2d7");

		String signString = signString(signParams);
		String sign = sign(signString.toString(), appsecret, HMAC_SHA256);
		// 根据业务自行https请求
//		请求头包含以下信息

		MediaType businessMediaType = MediaType.parse("application/json");
//		RequestBody smsBody = RequestBody.create(smsMediaType, "业务数据");
		String url = "https://yzstest.ynhtbank.com/dev/gateway/open/api/member/third/user?code=5484d3ddd671154439411b8a729cb2d7";
		Request businessRequest = new Request.Builder().url(url)// .method("POST", body)
				.addHeader("x-dv-timestamp", String.valueOf(timestamp)).addHeader("x-dv-appkey", appkey)
				.addHeader("x-dv-token", accessToken).addHeader("x-dv-nonce", nonce).addHeader("x-dv-sign", sign)
				.build();
		Response businessResponse = httpClient.newCall(businessRequest).execute();
		System.out.println(businessResponse.body().string());
	}

	public static String signString(Map<String, String> signParams) {
		StringBuilder signString = new StringBuilder();
		int i = 0;
		for (Entry<String, String> param : signParams.entrySet()) {
			if (i == 0) {
				signString.append(param.getKey() + "=" + param.getValue());
			} else {
				signString.append("&" + param.getKey() + "=" + param.getValue());
			}
			i++;
		}
		return signString.toString();
	}

	public static String sign(String data, String key, String method) throws Exception {
		Mac mac = Mac.getInstance(method);
		SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), mac.getAlgorithm());
		mac.init(secretKeySpec);
		byte[] hash = mac.doFinal(data.getBytes(StandardCharsets.UTF_8));
		return DatatypeConverter.printHexBinary(hash).toLowerCase();
	}

}
